import { _decorator, instantiate, ProgressBar, Tween, Vec3, tween, Label, director } from 'cc'
import { EntityManager } from '../../Base/EntityManager'
import { EntityTypeEnum, IActor, InputTypeEnum, toFixed } from '../../Common'
import { EntityStateEnum, EventEnum } from '../../Enum'
import DataManager from '../../Global/DataManager'
import EventManager from '../../Global/EventManager'
import { radToAngle } from '../../Utils'
import { WeaponManager } from '../Weapon/WeaponManager'
import { ActorStateMachine } from './ActorStateMachine'
const { ccclass } = _decorator

// 角色控制模块
@ccclass('ActorManager')
export class ActorManager extends EntityManager {
  // 角色数据
  id: number
  nickname: string
  type: EntityTypeEnum
  bulletType: EntityTypeEnum
  weaponType: EntityTypeEnum
  isDead = false

  // 武器控制
  private wm: WeaponManager
  // 血条节点
  private hp: ProgressBar
  // 名称节点
  private label: Label

  // 目标位置
  private targetPos: Vec3
  // 缓动动画
  private tw: Tween<unknown>

  init(data: IActor) {
    const { id, nickname, type, weaponType, bulletType } = data

    this.id = id
    this.nickname = nickname
    this.bulletType = bulletType
    this.weaponType = weaponType

    // 获取血条和名称节点
    this.hp = this.node.getComponentInChildren(ProgressBar)
    this.label = this.node.getComponentInChildren(Label)
    this.label.string = nickname

    // 绑定有限状态机
    this.fsm = this.addComponent(ActorStateMachine)
    // 初始化状态机
    this.fsm.init(type)
    // 初始化角色状态
    this.state = EntityStateEnum.Idle

    // 初始化角色武器
    const prefab = DataManager.Instance.prefabMap.get(this.weaponType)
    const weapon = instantiate(prefab)
    // 挂载到当前角色
    weapon.setParent(this.node)

    this.wm = weapon.addComponent(WeaponManager)
    this.wm.init(data)

    // 防止闪烁初始不可见
    this.node.active = false
    this.targetPos = undefined
  }
  // 帧同步
  tick(dt: number) {
    if (this.isDead) return
    if (this.hp?.progress <= 0) {
      return this.renderDead()
    }

    if (this.id !== DataManager.Instance.playerID) return

    if (DataManager.Instance.jm.input.length()) {
      const { x, y } = DataManager.Instance.jm.input
      // 向事件中心触发移动帧同步
      EventManager.Instance.emit(EventEnum.ClientSync, {
        type: InputTypeEnum.ActorMove,
        id: this.id,
        direction: { x: toFixed(x), y: toFixed(y) },
        dt: toFixed(dt),
      })
    }
  }
  // 更新渲染角色
  render(data: IActor) {
    this.renderPos(data)
    this.renderDir(data)
    this.renderHP(data)
  }
  // 渲染位置
  renderPos(data: IActor) {
    const { position } = data
    const newPos = new Vec3(position.x, position.y)

    // 初始化目标点
    if (!this.targetPos) {
      this.node.active = true
      this.node.setPosition(newPos)
      this.targetPos = newPos
      // 有新目标时开始移动动画
    } else if (!this.targetPos.equals(newPos)) {
      // tween 动画设置缓动
      this.tw?.stop()

      this.node.setPosition(this.targetPos)
      const distance = Math.sqrt((newPos.x - this.targetPos.x) ** 2 + (newPos.y - this.targetPos.y) ** 2)

      // 移动到上次目标位置(本地预测时，tw被无限取消，角色不能移动)
      this.targetPos.set(newPos)

      // 移动距离过小时不执行移动动画
      if (distance < 0.1) return (this.state = EntityStateEnum.Idle)

      // 移动动画
      this.state = EntityStateEnum.Run
      this.tw = tween(this.node)
        .to(0.1, {
          position: this.targetPos,
        })
        .call(() => {
          this.state = EntityStateEnum.Idle
        })
        .start()
    }

    // this.node.active = true
    // this.node.setPosition(newPos)
  }
  // 方向
  renderDir(data: IActor) {
    const { direction } = data
    // 左右方向切换
    if (direction.x !== 0) {
      this.node.setScale(direction.x > 0 ? 1 : -1, 1)
      this.label.node.setScale(direction.x > 0 ? 1 : -1, 1)
      this.hp.node.setScale(direction.x > 0 ? 1 : -1, 1)
    }
    //武器的旋转角度
    const rad = Math.asin(direction.y) // 单位向量:x**2+y**2=1
    const angle = radToAngle(rad)
    this.wm.node.setRotationFromEuler(0, 0, angle)
  }
  // 血量
  renderHP(data: IActor) {
    const { hp } = data
    this.hp.progress = hp / this.hp.totalLength
  }

  // 死亡状态
  renderDead() {
    this.isDead = true
    DataManager.Instance.deadNum++
    this.fsm.animationComponent.stop()
    this.label.string = this.nickname + '（已阵亡)'
    // const angle = radToAngle(Math.PI / 2)
    // this.node.setRotationFromEuler(0, 0, angle)
  }
}
